﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Refactored.Filters;
using Refactored.Models;

namespace Refactored.Controllers
{
    [Authorize]
    public class BookController : ApiController
    {
        private readonly BookContext
            _db = new BookContext();

        // GET api/Book
        public IEnumerable<BookDto> GetBooks()
        {
            return _db.Books
                .Where(u => u.UserId == User.Identity.Name)
                .OrderByDescending(u => u.BookId)
                .AsEnumerable()
                .Select(book => new BookDto(book));
        }

        // GET api/Book/5
        public BookDto GetBook(int id)
        {
            var book = _db.Books.Find(id);
            if (book == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            if (book.UserId != User.Identity.Name)
            {
                // Trying to modify a record that does not belong to the user
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized));
            }

            return new BookDto(book);
        }

        // PUT api/Book/5
        [ValidateHttpAntiForgeryToken]
        public HttpResponseMessage PutBook(int id, BookDto bookDto)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }

            if (id != bookDto.BookId)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            var book = bookDto.ToEntity();
            if (_db.Entry(book).Entity.UserId != User.Identity.Name)
            {
                // Trying to modify a record that does not belong to the user
                return Request.CreateResponse(HttpStatusCode.Unauthorized);
            }

            _db.Entry(book).State = EntityState.Modified;

            try
            {
                _db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError);
            }

            return Request.CreateResponse(HttpStatusCode.OK);
        }

        // POST api/Book
        [ValidateHttpAntiForgeryToken]
        public HttpResponseMessage PostBook(BookDto bookDto)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }

            bookDto.UserId = User.Identity.Name;
            var book = bookDto.ToEntity();
            _db.Books.Add(book);
            _db.SaveChanges();
            bookDto.BookId = book.BookId;

            var response = Request.CreateResponse(HttpStatusCode.Created, bookDto);
            response.Headers.Location = new Uri(Url.Link("DefaultApi", new {id = bookDto.BookId}));
            return response;
        }

        // DELETE api/Book/5
        [ValidateHttpAntiForgeryToken]
        public HttpResponseMessage DeleteBook(int id)
        {
            var book = _db.Books.Find(id);
            if (book == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            if (_db.Entry(book).Entity.UserId != User.Identity.Name)
            {
                // Trying to delete a record that does not belong to the user
                return Request.CreateResponse(HttpStatusCode.Unauthorized);
            }

            var bookDto = new BookDto(book);
            _db.Books.Remove(book);

            try
            {
                _db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError);
            }

            return Request.CreateResponse(HttpStatusCode.OK, bookDto);
        }

        protected override void Dispose(bool disposing)
        {
            _db.Dispose();
            base.Dispose(disposing);
        }
    }
}